package cc.rengu.igas.share.core.realize.impl;

import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.entity.RspCodeMap;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.MonitorModelInfo;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.service.realize.*;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.service.realize.impl.TransMonitorServiceImpl;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.*;

public class RiskMonitorServiceImpl implements RiskMonitorService {
    private final RgLogger rglog = RgLog.getLogger(this.getClass().getName());
    private static String ALARAM_LEVEL = "1";
    private static String RESP_CODE = OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespCode();
    private static String RESP_DESC = OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespDesc();

    @Override
    public boolean isMonitor() {
        try {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
            /* 获取交易监控推送开关及推送时间间隔 */
            SysParamService sysParamService = new SysParamServiceImpl();
            SysParam sysParam = sysParamService.getSysParamInfo(instId, AppParamConstant.PLAT_SYS_PARAM, AppParamConstant.TRANS_MONITOR_PUSH_FLAG);
            if (null != sysParam && AppParamConstant.YES.equals(sysParam.getParamValue().trim())) {
                String lastPushTimeKey = instId + AppParamConstant.LAST_MONITOR_PUSH_TIME;
                String lastPushTimeString = RedisUtil.hashGet(AppParamConstant.TRANS_MONITOR_CACHE, lastPushTimeKey);
                long lastPushTime = StringUtil.isEmptyOrNull(lastPushTimeString) ? 0L : Long.parseLong(lastPushTimeString);
                sysParam = sysParamService.getSysParamInfo(instId, AppParamConstant.PLAT_SYS_PARAM, AppParamConstant.TRANS_MONITOR_PUSH_GAP);
                int pushGatTime = null == sysParam ? 5 : Integer.parseInt(sysParam.getParamValue());
                /* 上次推送时间 + 推送间隔时间 小于当前系统时间时不推送 */
                if (System.currentTimeMillis() >= lastPushTime + pushGatTime * 1000L) {
                    RedisUtil.hashSet(AppParamConstant.TRANS_MONITOR_CACHE, lastPushTimeKey, String.valueOf(System.currentTimeMillis()));
                    return true;
                }
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.warn("获取交易监控推送开关异常,默认不推送,异常信息:<{}>", byteArrayOutputStream.toString());
            return false;
        }
        return false;
    }

    @Override
    public void monitorPush() {
        try {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
            /* Step1：获取所有交易监控模型配置信息 */
            SysParamService sysParamService = new SysParamServiceImpl();
            List<SysParam> sysParamList = sysParamService.getSysParamInfo(instId, AppParamConstant.PLAT_SYS_PARAM);
            if (!AppParamConstant.DEFAULT_INSTID.equals(instId)) {
                List<SysParam> sysParams = sysParamService.getSysParamInfo(AppParamConstant.DEFAULT_INSTID, AppParamConstant.PLAT_SYS_PARAM);
                if (null != sysParams && !sysParams.isEmpty()) {
                    if (null == sysParamList) {
                        sysParamList = new ArrayList<>();
                    }
                    sysParamList.addAll(sysParams);
                }
            }
            /* Step2：获取所有交易监控统计信息 */
            TransMonitorService transMonitorService = new TransMonitorServiceImpl();
            List<MonitorModelInfo> monitorModelInfoList = transMonitorService.getMonitorModelData(sysParamList);
            /* Step3：调用交易监控平台推送监控信息 */
            if (null != monitorModelInfoList && !monitorModelInfoList.isEmpty()) {
                /* Step3.1：获取交易监控推送URL */
                Optional<SysParam> sysParamOpt = sysParamList.stream().filter(item -> item.getParamKey().equals(AppParamConstant.TRANS_MONITOR_PUSH_URL)).findFirst();
                if (!sysParamOpt.isPresent()) {
                    rglog.error("未配置交易监控推送URl，不进行交易监控推送!");
                    return;
                }
                String pushUrl = sysParamOpt.get().getParamValue().trim();
                /* Step3.2：交易监控数据推送 */
                JSONArray jsonArray = new JSONArray();
                for (MonitorModelInfo monitorModelInfo : monitorModelInfoList) {
                    Map<String, String> monitorPushDataMap = new HashMap<>();
                    monitorPushDataMap.put("hawkId", monitorModelInfo.getMonitorModelId());
                    monitorPushDataMap.put("indexData", monitorModelInfo.getMonitorModelData());
                    jsonArray.add(monitorPushDataMap);
                }
                rglog.debug("推送交易监控数据:{}", JSON.toJSONString(jsonArray));
                Map<String, String> pushDataMap = new HashMap<>();
                pushDataMap.put("indexes", JSON.toJSONString(jsonArray));
                HttpUtil.postForm(pushUrl, pushDataMap);
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("推送交易监控信息异常:<{}>", byteArrayOutputStream.toString());
        }
    }

    @Override
    public boolean isAlarm() {
        try {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            String transStatus = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_STATUS);
            /* 只有交易失败的时候才校验是否推送风险监控 */
            if (!StringUtil.isEmptyOrNull(transStatus) && !TransStatusEnum.TRANS_SUCC.getStatus().equals(transStatus)){
                RspCodeMap rspCodeMap = (RspCodeMap) xmlTreeUtil.getXmlTreeObjectValue(TreeNodeConstant.RSP_CODE_MAP, RspCodeMap.class);
                if (null != rspCodeMap) {
                    /* 若存在错误码转换关系，则以错误码转换关系配置的告警级别进行告警 */
                    ALARAM_LEVEL = rspCodeMap.getRiskAlarmLevel().trim();
                    RESP_CODE = rspCodeMap.getDestRspCode();
                    RESP_DESC = rspCodeMap.getDestRspDesc();
                    String alarmFlag = rspCodeMap.getRiskAlarmFlag();
                    rglog.info("当前错误码<{}-{}>配置的告警开关为:{}，告警级别为:{}",RESP_CODE,RESP_DESC,alarmFlag,ALARAM_LEVEL);
                    return AppParamConstant.YES.equals(alarmFlag) && !StringUtil.isEmptyOrNull(ALARAM_LEVEL);
                }else {
                    /* 若不存在错误码转换关系，则默认按告警级别进行告警 */
                    RESP_CODE = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.RESP_CODE);
                    RESP_DESC = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.RESP_DESC);
                    return true;
                }
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("获取交易交易风险推送开关配置失败，默认不推送,异常信息:<{}>", byteArrayOutputStream.toString());
        }
        return false;
    }

    @Override
    public void alarmPush(String execptionMsg) {
        try {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
            String transStatus = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_STATUS);
            TxnInfo txnInfo = (TxnInfo) xmlTreeUtil.getXmlTreeObjectValue(TreeNodeConstant.TXN_INFO,TxnInfo.class);

            /* Step1：获取所有交易监控模型配置信息 */
            SysParamService sysParamService = new SysParamServiceImpl();
            List<SysParam> sysParamList = sysParamService.getSysParamInfo(instId, AppParamConstant.PLAT_SYS_PARAM);

            /* Step2：获取交易监控推送URL */
            Optional<SysParam> sysParamOpt = sysParamList.stream().filter(item -> item.getParamKey().equals(AppParamConstant.RISK_ALARM_PUSH_URL)).findFirst();
            SysParam pushUrlParam = sysParamOpt.orElse(null);
            sysParamOpt = sysParamList.stream().filter(item -> item.getParamKey().equals(AppParamConstant.RISK_ALARM_PUSH_MODEL_ID)).findFirst();
            SysParam riskModelPram = sysParamOpt.orElse(null);
            if (null == pushUrlParam || null == riskModelPram) {
                rglog.error("未配置风险告警推送模型及推送URl，不进行风险告警推送!");
                return;
            }

            /* Step3：风险监控数据赋值 */
            Map<String, String> alarmDataMap = new HashMap<>();
            alarmDataMap.put("txnNum", txnInfo.getSrcTxnAuthCfg().getTxnNum());
            alarmDataMap.put("txnName", txnInfo.getSrcTxnAuthCfg().getTxnName());
            alarmDataMap.put("alarmLevel", ALARAM_LEVEL);
            alarmDataMap.put("transStatus", transStatus);
            alarmDataMap.put("sysSeqNum",xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
            alarmDataMap.put("respCode", RESP_CODE);
            alarmDataMap.put("respDesc", RESP_DESC);
            alarmDataMap.put("exceptionMsg", execptionMsg);
            sysParamOpt = sysParamList.stream().filter(item -> item.getParamKey().equals(AppParamConstant.ALARM_PUSH_PHONE_NO)).findFirst();
            sysParamOpt.ifPresent(sysParam -> alarmDataMap.put("alarmPhoneNo", sysParam.getParamValue()));
            sysParamOpt = sysParamList.stream().filter(item -> item.getParamKey().equals(AppParamConstant.ALARM_PUSH_EMAIL)).findFirst();
            sysParamOpt.ifPresent(sysParam -> alarmDataMap.put("alarmEmail", sysParam.getParamValue()));

            /* Step4：风险监控数据推送 */
            Map<String, String> pushDataMap = new HashMap<>();
            pushDataMap.put("modelKey",riskModelPram.getParamValue().trim());
            pushDataMap.put("jsonData", JSON.toJSONString(alarmDataMap));
            rglog.debug("风险告警推送,URL:{},告警数据:{}",pushUrlParam.getParamValue().trim(), JSON.toJSONString(pushDataMap));
            HttpUtil.postForm(pushUrlParam.getParamValue().trim(), pushDataMap);
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("调用告警平台异常:<{}>", byteArrayOutputStream.toString());
        }
    }

    @Override
    public boolean isRiskTrans() {
        return false;
    }

    @Override
    public boolean isRiskCollect() {
        try {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
            SysParamService sysParamService = new SysParamServiceImpl();
            SysParam sysParam = sysParamService.getSysParamInfo(instId, AppParamConstant.PLAT_SYS_PARAM, AppParamConstant.TRANS_RISK_COLLECT_FLAG);
            if (null != sysParam && AppParamConstant.YES.equals(sysParam.getParamValue().trim())) {
                return true;
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.warn("获取交易风险信息采集开关异常,默认不采集,异常信息:<{}>", byteArrayOutputStream.toString());
            return false;
        }
        return false;
    }

    @Override
    public void riskCollectPush(Map<String, String> message) {

    }
}
